#ifndef _DDR_SSD_H
#define _DDR_SSD_H

#include "SSD_define.h"
#include "SDRAM_DDR_device_if.h"
#include "NAND_device_if.h"
#include "SDRAM_DDR_DP_device_if.h"

//#define DEBUG_DDR_SSD
//#define DEBUG_DDR_SSD_SDRAM_CTRL

const unsigned DDR_SSD_FULL_PAGE_BURST_LENGTH = CRC_BUFFER/2;
const unsigned MAX_BUFFER_DDR_SSD	= 16;

class DDR_SSD
: public sc_module
, public SDRAM_DDR_device_if
{
public:
	sc_in_clk	DRAM_CLK;
	sc_in_clk	FLASH_CLK;
	sc_in<bool> RSTn;

	sc_port<NAND_device_if, 1> NAND_port_1;
	sc_port<NAND_device_if, 1> NAND_port_2;
	sc_port<SDRAM_DDR_DP_device_if, 1> DRAM_port;

	const bool
	SDRAM_refresh(bool	refresh_type_);

	const bool
	SDRAM_row_activate(unsigned		rank_sel_,
					   unsigned		bank_sel_,
					   SDRAM_addr_t	row_addr_);

	const bool
	SDRAM_read_command(unsigned		rank_sel_,
					   unsigned		bank_sel_,
					   SDRAM_addr_t	col_addr_,
					   bool			auto_precharge_);

	const bool
	SDRAM_write_command(unsigned		rank_sel_,
						unsigned		bank_sel_,
						SDRAM_addr_t	col_addr_,
						bool			auto_precharge_);

	const bool
	SDRAM_precharge(unsigned	rank_sel_,
					unsigned	bank_sel_,
					bool		precharge_all_);

	const bool
	SDRAM_DDR_mode_register_set(unsigned		EMRS_num_,
								unsigned short	EMRS_code_);

	const SDRAM_DDR_data_t
	SDRAM_DDR_read_data(unsigned	rank_sel_,
						unsigned	bank_sel_,
						unsigned	current_burst_,
						bool		direct_access_);

	const bool
	SDRAM_DDR_write_data(unsigned			rank_sel_,
						 unsigned			bank_sel_,
						 unsigned			current_burst_,
						 SDRAM_DDR_data_t	data_,
						 bool				direct_access_);

	const sc_logic
	SDRAM_DDR_get_DQS() const;

	const bool
	SDRAM_DDR_set_DQS(sc_logic	DQS_);

	SC_HAS_PROCESS(DDR_SSD);

	DDR_SSD(sc_module_name	name_,
			unsigned		SSD_DMA_PRD_start_addr_,
			unsigned		Main_SSD_DMA_cmd_reg_start_addr_,
			unsigned		Main_DMA_check_reg_start_addr_,
			unsigned		System_type_,
			unsigned		DRAM_rank_index_,
			unsigned		DRAM_bank_index_,
			unsigned		DRAM_row_index_,
			unsigned		DRAM_col_index_);
	
	~DDR_SSD();

protected:
	unsigned					System_type;

	SDRAM_DDR_mode_register_t	SSD_mode_register;
	sc_logic					SSD_DQS;

	unsigned					DRAM_rank_index;
	unsigned					DRAM_bank_index;
	unsigned					DRAM_row_index;
	unsigned					DRAM_col_index;
	
	unsigned					LBA_write;
	unsigned					LBA_read;
	unsigned					LBA_write_temp;
	unsigned					LBA_read_temp;

	SDRAM_state_t				DRAM_curr_state;
	bool						DRAM_refresh_enable;

	const char*
	SDRAM_get_state_name(SDRAM_state_t	state_) const;

	void
	DRAM_timing_control_action();

	unsigned		SSD_DMA_PRD_start_addr;
	unsigned		SSD_DMA_PRD_start_addr_init;
	unsigned		Main_SSD_DMA_cmd_reg_start_addr;
	unsigned		Main_DMA_check_reg_start_addr;

	unsigned		SSD_write_end;

	unsigned		SSD_DMA_command;
	unsigned		SSD_DMA_sector_cnt;
	unsigned		SSD_DMA_LBA;
	unsigned		SSD_DMA_LBA_current;
	unsigned		SSD_DMA_PRD_length;

	unsigned		SSD_DMA_base_addr;
	unsigned		SSD_DMA_base_cnt;

	unsigned		SSD_DMA_end;

	bool			SSD_DMA_enable;
	sc_time			SSD_DMA_enable_time;
	bool			SSD_DMA_PRD_fetched;
	sc_time			SSD_DMA_PRD_fetched_time;
	bool			SSD_DMA_buffered;
	sc_time			SSD_DMA_buffered_time;

	unsigned		PRD_current;

	void
	Cache_arbiter_action();

	bool		C_WRITE, C_READ;

	bool		DRAM_or_SSD;
	bool		SSD_Cache_WR_request;
	bool		SSD_Cache_RD_request;
	bool		DRAM_Cache_WR_request;
	bool		DRAM_Cache_RD_request;
	bool		SSD_Cache_finished;
	bool		DRAM_Cache_finished;

	unsigned	SSD_WR_FIFO[CRC_BUFFER];
	unsigned	SSD_WR_pOUT;
	unsigned	SSD_WR_pIN;

	unsigned	SSD_RD_FIFO[CRC_BUFFER];
	unsigned	SSD_RD_pOUT;
	unsigned	SSD_RD_pIN;

	unsigned	DMA_SSD_RD_Buffer[MAX_BUFFER_DDR_SSD][CRC_BUFFER];
	unsigned	DMA_SSD_RD_Buffer_pOUT;
	unsigned	DMA_SSD_RD_Buffer_pIN;

	unsigned	DRAM_WR_FIFO[CRC_BUFFER];
	unsigned	DRAM_WR_pOUT;
	unsigned	DRAM_WR_pIN;

	unsigned	DRAM_RD_FIFO[CRC_BUFFER];
	unsigned	DRAM_RD_pOUT;
	unsigned	DRAM_RD_pIN;

	unsigned	DMA_DRAM_RD_Buffer[MAX_BUFFER_DDR_SSD][CRC_BUFFER];
	unsigned	DMA_DRAM_RD_Buffer_pOUT;
	unsigned	DMA_DRAM_RD_Buffer_pIN;

	unsigned	CH1_Buffer[CRC_BUFFER];
	unsigned	CH1_Buffer_pOUT;
	unsigned	CH1_Buffer_pIN;

	unsigned	CH2_Buffer[CRC_BUFFER];
	unsigned	CH2_Buffer_pOUT;
	unsigned	CH2_Buffer_pIN;

	unsigned	SRAM_Array[CACHE_BUFFER];
	unsigned	decision[CACHE_BUFFER/CRC_BUFFER];

	const bool
	Cache_decision(unsigned	LBA_) const;

	void
	Cache_process();

	bool F_WRITE_1;
	bool F_READ_1;
	bool F_ERASE_1;
	bool F_WRITE_2;
	bool F_READ_2;
	bool F_ERASE_2;

	FLASH_state_t current_state_1;
	FLASH_state_t current_state_2;

	unsigned cmd_1;
	unsigned cmd_2;
	unsigned DATA_cnt_1;
	unsigned DATA_cnt_2;
	unsigned DATA_word_1;
	unsigned DATA_word_2;
	bool Confirm_commanded_1;
	bool Confirm_commanded_2;
	bool cache_buffer_read_1;
	bool cache_buffer_read_2;

	unsigned CA, PA, BA;
	byte col_addr0, col_addr1, row_addr0, row_addr1;

	void
	FLASH_addr_gen(unsigned	LBA_);

	void
	FLASHcontroller_process_1();

	void
	FLASHcontroller_process_2();
};

#endif
